package cn.com.egova.skinapplication.skin;

import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.AsyncTask;

import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.com.egova.skinapplication.skin.attr.SkinView;
import cn.com.egova.skinapplication.skin.callback.ISkinChangedListener;
import cn.com.egova.skinapplication.skin.callback.ISkinChangingCallback;
import cn.com.egova.skinapplication.skin.config.Constant;

/**
 * Created by yuanchao on 2017/3/12.
 */

public class SkinManager {
    public static SkinManager sInstance;
    private Context mContext;
    private ResourceManager mResourceManager;

    //key实际上就是所有Activity,由于SkinManager生命周期很长,几乎和应用一样长,而mSkinViewMaps中的键值对中的key对Activity产生了强引用,
    //必然引起内存泄漏.因此需要进行优化,优化的原理就是观察者模式,Activity销毁时,mSkinViewMaps里也应移除其实例.
    private Map<ISkinChangedListener,List<SkinView>>  mSkinViewMaps = new HashMap<ISkinChangedListener,List<SkinView>>();

    private List<ISkinChangedListener> mListeners = new ArrayList<ISkinChangedListener>();

    private PrefUtils mPrefUtils;

    private String mCurPath;
    private String mCurPkg;
    private String mSuffix;

    private SkinManager() {

    }

    public static SkinManager getInstance() {
        if (sInstance == null) {
            synchronized (SkinManager.class) {
                if (sInstance == null) {
                    sInstance = new SkinManager();
                }
            }
        }
        return sInstance;
    }


    public void init(Context context){
        //这里用getApplicationContext,因为你传入的很可能是一个Activity对象,它的生命周期太短,SkinManager是一个全局的单例类,
        //所以生命周期尽可能长.
        mContext = context.getApplicationContext();
        mPrefUtils = new PrefUtils(context);

        try {
            String pluginPath = mPrefUtils.getPluginPath();
            String pluginPkg = mPrefUtils.getPluginPkg();
            mSuffix = mPrefUtils.getSuffix();

            File file = new File(pluginPath);
            if(file.exists()){
                loadPlugin(pluginPath,pluginPkg);
            }

        } catch (Exception e) {
            e.printStackTrace();
            mPrefUtils.clear();
        }
    }


    /**
     * 获取ResourceManager,包括用于获取插件资源的ResourceManager和用于应用内换肤的ResourceManager.
     * @return
     */
    public ResourceManager getResourceManager(){
        if(!usePlugin()){
            //如果不是使用插件换肤,对本例则是应用内换肤,返回本应用的ResourceManager.
            return new ResourceManager(mContext.getResources(),mContext.getPackageName(), mSuffix);
        }
        return mResourceManager;
    }


    /**
     * 加载插件,本方法内并未真正换肤和获取资源,仅仅是添加资源路径,获取ResourceManager实例,
     * 对mCurPath和mCurPkg重新进行赋值.
     * @param skinPluginPath
     * @param skinPluginPkg
     * @return
     */
    private int loadPlugin(String skinPluginPath, String skinPluginPkg) {
        try {
            if(skinPluginPath.equals(mCurPath) && skinPluginPkg.equals(mCurPkg)){
                return Constant.RESULT_REPEAT;
            }

            AssetManager assetManager = AssetManager.class.newInstance();
            Method addAssetPathMethod = AssetManager.class.getMethod("addAssetPath", String.class);
            addAssetPathMethod.invoke(assetManager, skinPluginPath); //添加资源路径.

            Resources superResource = mContext.getResources();
            Resources resources = new Resources(assetManager, superResource.getDisplayMetrics(), superResource.getConfiguration());
            mResourceManager = new ResourceManager(resources, skinPluginPkg,null);

            mCurPath = skinPluginPath;
            mCurPkg = skinPluginPkg;

            return Constant.RESULT_SUCCESS;
        } catch (Exception e) {
            e.printStackTrace();
            return Constant.RESULT_FAILED;
        }
    }


    public List<SkinView> getSkinViews(ISkinChangedListener listener){
        return mSkinViewMaps.get(listener);
    }


    public void addSkinView(ISkinChangedListener listener,List<SkinView> views){
        mSkinViewMaps.put(listener,views);
    }


    public void registerListener(ISkinChangedListener listener){
        mListeners.add(listener);
    }

    public void unRegisterListener(ISkinChangedListener listener){
        mListeners.remove(listener);
        mSkinViewMaps.remove(listener);
    }

    /**
     * 应用内换肤,速度比较快,不需要callback.
     * @param suffix
     */
    public void changeSkin(String suffix){
        clearPluginInfo();
        mSuffix = suffix;
        mPrefUtils.saveSuffix(suffix);
        notifyChangedListener();
    }

    private void clearPluginInfo() {
        mCurPath = null;
        mCurPkg = null;
        mSuffix = null;
        mPrefUtils.clear();
    }

    public void changeSkin(final String skinPluginPath, final String skinPluginPkg, ISkinChangingCallback callback) {
        if(callback==null){
            callback=ISkinChangingCallback.DEFAULT_CALLBACK;
        }
        final ISkinChangingCallback finalCallback = callback;

        new AsyncTask<Void,Void,Integer>(){

            @Override
            protected Integer doInBackground(Void... params) {
                try {
                    //注意这里边并未真正换肤,只是创建了ResourceManager的实例, 并且对mCurPath,mCurPkg进行重新赋值.
                    int resultCode = loadPlugin(skinPluginPath,skinPluginPkg);
                    return resultCode;
                } catch (Exception e) {
                    e.printStackTrace();
                    return Constant.RESULT_FAILED;
                }
            }

            @Override
            protected void onPostExecute(Integer code) {
                if(code==Constant.RESULT_FAILED){
                    finalCallback.onError();
                    return;
                }

                if(code==Constant.RESULT_REPEAT){
                    finalCallback.onRepeat();
                    return;
                }

                try {
                    notifyChangedListener();  //完成真正的换肤.
                    finalCallback.onComplete(); //回调
                    updatePluginInfo(skinPluginPath,skinPluginPkg);     //存储插件信息
                } catch (Exception e) {
                    e.printStackTrace();
                    finalCallback.onError();
                }
            }

        }.execute();
    }


    /**
     * 保存皮肤插件相关信息,注意这里不用保存suffix,因为当应用内换肤时会直接清空首选项.
     * @param path
     * @param pkg
     */
    private void updatePluginInfo(String path,String pkg) {
        mPrefUtils.savePluginPath(path);
        mPrefUtils.savePluginPkg(pkg);
    }


    private void notifyChangedListener() {
        for(ISkinChangedListener listener:mListeners){
            skinChange(listener);
            listener.onSkinChanged();
        }
    }


    public void skinChange(ISkinChangedListener listener) {
        List<SkinView> skinViews = mSkinViewMaps.get(listener);
        for(SkinView skinView:skinViews){
            skinView.apply();
        }
    }

    public boolean isNeedChangeSkin() {
        return usePlugin() || useSuffix();
    }

    private boolean usePlugin(){
        return mCurPath!=null && !mCurPath.trim().equals("");
    }

    private boolean useSuffix(){
        return mSuffix!=null && !mSuffix.trim().equals("");
    }
}
